from flask import g
from flask import render_template, current_app, jsonify
# ----2 导入蓝图对象使用蓝图
from flask import request

from . import news_blue
from flask import session
from info.models import User, News, Category,Comment
from info.utils.response_code import RET
# 导入装饰其函数f
from info.utils.commons import login_required
from info import db


# 检查用户是否登陆
@news_blue.route('/')
@login_required
def hello_world():
    # 首页右上角 检查用户登陆状态 显示用户信息  如果未登录 提供登陆注册接口
    # 从redis中获取用户id
    # 根据user_id查询mysql 用户信息
    # 把用户信息 传送给模板 进行渲染

    # 第二
    # 新闻点击排行
    # 根据新闻的点击次数 机查询数据库 使用模板渲染展示
    # 01 首先根据获取user_id
    # user_id = session.get('user_id')
    # # print(session)
    # # print('user_id',user_id)
    # user = None
    # # 根据获取道德user_id 从mysql中查询用户信息
    # if user_id:
    #     try:
    #         user = User.query.get(user_id)
    #         # print('user', user)
    #     except Exception as e:
    #         current_app.logger.error(e)

    # print(user)
    user = g.user
    # 在数据库中查询 新闻的点击次数 根据所有的点击次数进行倒叙排序
    try:
        # 这里获取到 的数据是一个对象 并且是很多数据
        news_list = News.query.order_by(News.clicks.desc()).limit(6)
    except Exception as e:
        current_app.logger.error(e)
        return jsonify(errno=RET.DBERR, errmsg='查询数据错误')
    # 判断获取导的对象是否为空
    if not news_list:
        return jsonify(errno=RET.NODATA, errmsg='没有新闻排行数据')
    # 如果有数据 定义一个容器存储数据 进行便利 然后每个都调用to——dict进行显示
    new_click_list = []
    for i in news_list:
        new_click_list.append(i.to_dict())

    # 新闻分类展示
    # 新闻分类展示 就是查询到 所有的分类 数据
    try:
        # 查询到所有分类数据
        categories = Category.query.all()
    except Exception as e:
        current_app.logger(e)
        return jsonify(RET.DBERR, errmsg='分类数据查询失败')
    if not categories:
        return jsonify(RET.PARAMERR, errmsg='分类数据不存在')
    # 如果分类数据存在 循环便利除每一条分类类型
    categories_list = []
    for categor in categories:
        # 便利出来的每个对象 调用函数 进行显示
        categories_list.append(categor.to_dict())

    # 定义字典用来返回数据
    data = {'user_info': user.to_dict() if user else None
        , 'new_click_list': new_click_list,
            'categories_list': categories_list}
    # print(data)
    # print(categories)
    return render_template('news/index.html', data=data)


# 加载分类新闻数据 其实就是 当你点击那个分类的时候 就需要从数据库中查询到那个类型的数据/ 然后
# 返回数据  但是分类需要一个东西来标示

@news_blue.route('/news_list')
def news_list():
    # 获取参数  检查参数 业务处理 返回参数
    # 01 需要获取到的参数是 get 请求 cid 是什么分类id类型  page 总页数  page_per 当前页数
    # 02 检查分类id  这个分类id 必须是整形值 并且也是 总分类类型中的类型
    # cid,page,page_per = int(cid),int(page),int(page_per) 如果传个不是整形值 所以需要进行异常处理

    # 03 根据分类id 查询新闻列表数据库
    # 首先是查找默认的所有新闻 并且按照发布时间进行倒序排序
    # 首先判断用户cid是否大于1
    # 然后根据传过来的分类id 来进行数据库的查找
    # 新闻表中 新闻类型是cid 根据创建时间倒序排序 并且分页显示 paginate 当前页数 总页数  分页错误不报错

    # if cid>1:
    # News.query.filter(News.category_id = cid).order_by(News.create_time.desc()).paginate（page,per_page,False）
    # else：
    # News.query.filter().order_by(News.create_time.desc()).paginate(page,per_page,False)

    # paginate 获取到的是一个对象 所以需要获取分页后的总数据
    # paginate.itmes() 全部数据
    # paginate.page() 获取当前数据
    # paginate.pages()获取总页数
    # 便利所有数据 然后电泳to_dict 转成字典
    # 返回数据

    # 获取数据 默认给一个1
    cid = request.args.get('cid', '1')
    page = request.args.get('page', '1')
    per_page = request.args.get('per_page', '10')

    # 检查参数
    # 强转数据
    try:
        cid, page, per_page = int(cid), int(page), int(per_page)
    except Exception as e:
        current_app.logger.error(e)
        return jsonify(errno=RET.DATAERR, errmsg='参数错误')
    # print(cid)
    filters = []
    # 如果cid不是大于1 的那么查询数据库就是所有数据按照排序的数据 就是页面上展示的最新的数据
    if cid > 1:
        filters.append(News.category_id == cid)

        # try:
        #     # 判断新闻类型id
        #     paginate = News.query.filter(News.category_id==cid).order_by(News.create_time.desc()).paginate(page,per_page,False)
        # except Exception as e:
        #     current_app.logger.error(e)
        #     return jsonify(RET.PARAMERR,errmsg = '查询数据失败')
    try:
        paginate = News.query.filter(*filters).order_by(News.create_time.desc()).paginate(page, per_page, False)
    except Exception as e:
        current_app.logger.error(e)
        return jsonify(errno=RET.DBERR, errmsg='查询数据失败')
    # 使用对象得到所有数据 所有页数 当前页数
    news_list = paginate.items
    total_page = paginate.pages
    current_page = paginate.page
    news_dict_list = []
    # 循环得到每个对象 然后调用to_dict函数
    # 需要一个容器 来存储得到的每个数据
    for news in news_list:
        # 每一条对象进行显示
        news_dict_list.append(news.to_dict())

    # 定义一个字典返回数据

    data = {
        'news_dict_list': news_dict_list,
        'total_page': total_page,
        'current_page': current_page
    }
    return jsonify(errno=RET.OK, errmsg='Ok', data=data)


# 新闻详情显示
# 相当于还是访问首页 带着参数来
@news_blue.route("/<int:news_id>")
@login_required
def news_detail(news_id):
    # user_id = session.get('user_id')
    # # print(session)
    # # print('user_id',user_id)
    # user = None
    # # 根据获取道德user_id 从mysql中查询用户信息
    # if user_id:
    #     try:
    #         user = User.query.get(user_id)
    #         # print('user', user)
    #     except Exception as e:
    #         current_app.logger.error(e)
    #
    #     # print(user)
    # 点击排行
    user = g.user
    # 在数据库中查询 新闻的点击次数 根据所有的点击次数进行倒叙排序
    try:
        # 这里获取到 的数据是一个对象 并且是很多数据
        news_list = News.query.order_by(News.clicks.desc()).limit(6)
    except Exception as e:
        current_app.logger.error(e)
        return jsonify(errno=RET.DBERR, errmsg='查询数据错误')
    # 判断获取导的对象是否为空
    if not news_list:
        return jsonify(errno=RET.NODATA, errmsg='没有新闻排行数据')
    # 如果有数据 定义一个容器存储数据 进行便利 然后每个都调用to——dict进行显示
    new_click_list = []
    for i in news_list:
        new_click_list.append(i.to_dict())

    # 根据前news_id 查找数据库中的新闻内容


    # 查询数据库
    # print(news_id)
    try:
        news = News.query.get(news_id)
        # print(news)
    except Exception as e:
        # current_app.logger.error(e)
        return jsonify(errno=RET.DBERR, errmsg='查询数据库失败')

    if not news:
        return jsonify(errno=RET.NODATA, errmsg='数据不存在')
    # 如果新闻存在 那马点击次数应该加上1
    news.clicks += 1
    # 将改变的数据添加到数据库中
    try:
        db.session.add(news)
        db.session.commit()
    except Exception as e:
        current_app.logger.error(e)
        db.session.rollback()
        return jsonify(errno=RET.DBERR, errmsg='保存数据失败')

    # 这是点击新闻详情的时候 用来判断用户是否收藏 然后改变小图标
    # 查看评论 并且展示
    # 获取评论数据
    try:
        comment_list = Comment.query.filter(Comment.news_id == news_id).order_by()
    except Exception as e:
        current_app.logger.error(e)
        return jsonify(errno = RET.DBERR,errmsg = '查询数据失败')
    # 定义一个容器来保存查询到的评论
    comments = []
    if comment_list:
        for i in comment_list:
            comments.append(i.to_dict())



    # 进入页面 直接看是否收藏
    # 定义一个标记 来判断用户是否收藏
    is_collected = False
    # 然后判断用户是否登陆 如果用户登陆 并且这个新闻在用户收藏列表中
    if g.user and news in user.collection_news:
        # 将is_collected 改为Ture
        is_collected = True








    # 如果有数据定义一个容器 返回数据
    data = {
        'news_detail': news.to_dict(),
        'user_info': user.to_dict() if user else None
        ,'new_click_list': new_click_list,
        # 这里记得返回参数
        'is_collected':is_collected,
        'comments':comments

    }

    # print(news.to_dict())
    # 传入模板
    return render_template('news/detail.html', data=data)


# 用户点击收藏或者取消收藏
@news_blue.route('/news_collect',methods = ['POST'])
@login_required
def user_collected():
    #  用户收藏与取消收藏
    # 1 判断用户是否登陆  如果没有登陆则不可以收藏 返回错误信息
    # 2 获取新闻id 和 action[collect,cancle_collect]
    # 3 检查参数的完整性 转换成int类型
    # 4判断用户选则的是收藏还是取消收藏 收藏的话就添加这个新闻导这个用户的信息中 否则
    # 就从用户收藏的新闻中移除这条新闻


    # 判断是否登陆
    # 空值代表未登录
    user = g.user
    if not user:
        return jsonify(errno = RET.SESSIONERR,errmsg = '用户未登录')
    # 获取参数
    news_id = request.json.get('news_id')
    action = request.json.get('action')
    print(news_id)
    print(action)
    # 检查参数 news_id  action 如果两个参数缺失 直接返回 一起检查需要用列表
    if not all([news_id,action]):
        return jsonify(errno = RET.PARAMERR,errmsg = '参数缺失')
    # 如果不缺失  则转换数据类型
    try:
        news_id = int(news_id)
    except Exception as e:
        current_app.logger.error(e)
        return jsonify(errno=RET.PARAMERR, errmsg='参数类型错误')
    # 接下来则判断action是什么参数 是收藏参数 collect 还是 取消参数cancel_collect
    # action 参数不在这个范围内 则返回错误
    if action not in ['collect','cancel_collect']:
        return jsonify(errno=RET.PARAMERR, errmsg='参数格式错误')

    # 根据news_id来查询新闻 确认新闻的存在
    try:
        news = News.query.get(news_id)
    except Exception as e:
        current_app.logger(e)
        return jsonify (errno=RET.DBERR, errmsg='查询数据库失败')
    # 如果新闻是空值
    if not news:
        return jsonify (errno=RET.NODATA, errmsg='新闻不存在')
    # 然后判断用户是否收藏
    # 如果是收藏
    if action == 'collect':
        # 判断用户没有收藏过
        if news not in user.collection_news:
            # 如果没有添加过则添加  关系引用都是列表 所以使用append进行添加
            user.collection_news.append(news)
    # 如果是取消
    else:
        user.collection_news.remove(news)
    # 最后将数据提交数据库
    try:
        db.session.add(news)
        db.session.commit()
    except Exception as e:
        current_app.logger.error(e)
        return jsonify(errno = RET.DBERR, errmsg='保存数据错误')
    # 这里需要两个返回
    return jsonify(errno = RET.OK, errmsg='ok')


# 新闻评论显示
@news_blue.route('/news_comment',methods = ['POST'])
@login_required
def news_comments():
    # 新闻评论
    # 获取参数  检查参数  业务处理  返回参数

    # 01  接受到的参数有 新闻id  news_id   以及新闻评论的内容  comment  parent_id
    # 02 检查参数  他的福评论id 可有可无 因为他有可能评论的是这条新闻 或者其他人的评论
    # 03 转换数据参数的数据类型 并且判断 panent_id是否存在
    # 04  需要查询新闻是否存在
    # 05 保存评论信息 判断parent_id 是否存在
    # 06 提交数据到mysql数据库
    # 07 返回结果

    # 01 首先评论时需要先判断用户是否登陆的
    user = g.user
    if not user:
        return jsonify(errno = RET.SESSIONERR,essmsg = '清闲登陆')
    # 获取这三个参数
    news_id = request.json.get('news_id')
    content = request.json.get('comment')
    parent_id = request.json.get('parent_id')
    print(news_id,content,parent_id)

    # 检查参数
    if not all([news_id,content]):
        return jsonify(errno=RET.PARAMERR,errmsg='参数缺失')
    # 转换数据类型
    try:
        news_id  = int(news_id)
        # 如果有父评论id 则转换
        if parent_id:
            parent_id = int(parent_id)
    except Exception as e:
        current_app.logger.error(e)
        return jsonify(errno=RET.PARAMERR, errmsg='参数类型错误')
    # 查询数据库 确认新闻的存在
    try:
        news = News.query.get(news_id)
    except Exception as e:
        current_app.logger.error(e)
        return jsonify(errno=RET.DBERR, errmsg='查询新闻数据失败')
    if not news:
        return jsonify(errno=RET.NODATA,errmsg='无新闻数据')
    # 构造评论模型类对象  然后对数据进行提交
    comment = Comment()
    # 这个人的id 这条新闻的id 这条新闻的内容
    comment.user_id = user.id
    comment.news_id = news.id
    comment.content = content
    # 判断是否存在 父评论
    if parent_id:
        comment.parent_id = parent_id
    # 提交数据导数据库
    try:
        db.session.add(comment)
        db.session.commit()
    except Exception as e:
        current_app.logger.error(e)
        # 操作失败 进行回滚
        db.session.rollback()
        return jsonify(errno=RET.DBERR,errmsg='保存评论数据失败')
    return jsonify(errno=RET.OK,errmsg='OK',data = comment.to_dict())










# 加载logo图标 浏览器会默认请求
@news_blue.route('/favicon.ico')
def favicon():
    # 把favicon图标传递给浏览器他默认访问的路径为http://127.0.0.1:5000/static/news/favicon.ico
    # 如果没显示图标
    # 浏览器不是每次请求 而是使用缓存
    # 清楚浏览器缓存
    # 彻底退出浏览器
    return current_app.send_static_file('news/favicon.ico')
